import { notDeepEqual } from "assert";

declare const wx: any;

interface KVData {
    key: string;
    value: string;
}

interface UserInfo {
    openId: string;
    nickName: string;
    avatarUrl: string;
    gender: number;
}

interface UserGameData {
    openid: string;
    nickname: string;
    avatarUrl: string;
    KVDataList: KVData[];
}

export interface RankItemData {
    nickName: string,
    avatarUrl: string,
    score: number,
}

export interface RankData {
    selfIndex: number,
    items: RankItemData[]
}

const SCOREKEY = 'score';

const { ccclass, property } = cc._decorator;

@ccclass
export default class OpenData extends cc.Component {

    private _nickName: string = '';
    private _friendRankData: RankData = { selfIndex: -1, items: [] };
    private _avatarUrl = '';
    private _maxScore = -1;

    @property(cc.Node)
    wxDataDispatcher: cc.Node = null

    start() {
        this.node.active = true;
        let self = this;
        this.wxDataDispatcher.on('uploadScore', (e: cc.Event.EventCustom) => {
            const data = e.detail
            self._uploadScore(data.value);
        });
        this.wxDataDispatcher.on('showRankGroup', (e: cc.Event.EventCustom) => {
            self._showRankGroup(e.detail.shareTicket);
        });
        this.wxDataDispatcher.on('showRankAll', (e: cc.Event.EventCustom) => {
            self.node.emit('showRankAll', e.detail.rankData);
        });
        this.wxDataDispatcher.on('showRankList', (e: cc.Event.EventCustom) => {
            self.node.emit('showRankList');
        });
        this.wxDataDispatcher.on('hideRankList', (e: cc.Event.EventCustom) => {
            self.node.emit('hideRankList');
        });
        this.wxDataDispatcher.on('disableRankList', (e: cc.Event.EventCustom) => {
            self.node.emit('disableRankList');
        });
        this.wxDataDispatcher.on('showRankFriendTop', (e: cc.Event.EventCustom) => {
            self.node.emit('showRankFriendTop', this._friendRankData);
        });
        this.wxDataDispatcher.on('showRankFriend', (e: cc.Event.EventCustom) => {
            self.node.emit('showRankFriend', this._friendRankData);
        });
        self._resetFriendRank();
    }

    private _uploadScore(score: number) {
        if (score > this._maxScore) {
            this._maxScore = score;
            wx.setUserCloudStorage({
                KVDataList: [{ key: SCOREKEY, value: score.toString() }],
                success: (resp) => {
                    resp && cc.log(resp);
                    this._resetFriendRank();
                },
                fail: cc.warn
            });
        }
    }

    private _setSelfRank(rankData: RankData) {
        for (let ix = 0; ix < rankData.items.length; ix++) {
            const element = rankData.items[ix];
            if (element.avatarUrl === this._avatarUrl) {
                rankData.selfIndex = ix;
                (element.score > this._maxScore) && (this._maxScore = element.score);
                break;
            }
        }
        if (rankData.selfIndex === -1) {
            // 把自己加入到排行榜
            rankData.selfIndex = rankData.items.length;
            rankData.items.push({
                nickName: this._nickName,
                avatarUrl: this._avatarUrl,
                score: 0,
            });
        }
    }

    private _getSelfInfo() {
        return new Promise<UserInfo>((resolve, reject) => {
            wx.getUserInfo({
                openIdList: ['selfOpenId'],
                lang: 'zh_CN',
                success: resp => resp.data.length > 0 && resolve(resp.data[0]),
                complete: reject
            });
        });
    }

    private async _initUserInfo() {
        try {
            let info = await this._getSelfInfo();
            this._avatarUrl = info.avatarUrl;
            this._nickName = info.nickName;
            this._setSelfRank(this._friendRankData);
            this.node.emit('resetUserInfo');
        } catch (error) {
            cc.warn(error);
        }
    }

    private async _resetFriendRank() {
        (!this._avatarUrl) && this._initUserInfo();
        try {
            let data = await this._getFriendScore();
            this._friendRankData = this._getRank(data);
            this.node.emit('resetFriendRank', this._friendRankData);
        } catch (error) {
            cc.warn(error);
        }
    }

    private _getFriendScore() {
        return new Promise<UserGameData[]>((resolve, reject) => {
            wx.getFriendCloudStorage({
                keyList: [SCOREKEY],
                success: resp => resolve(resp.data),
                fail: reject,
            });

        })
    }

    private _getRank(data: UserGameData[]) {
        let cmp = (i: { score?: number }, j: { score?: number }) => {
            if (i.score && j.score) {
                return j.score - i.score;
            } else if (i.score) {
                return -1;
            } else {
                return 1;
            }
        }
        let getScore = (kvList: KVData[]) => {
            for (let ix = 0; ix < kvList.length; ix++) {
                const element = kvList[ix];
                if (element.key === SCOREKEY) {
                    return parseInt(element.value) || 0;
                }
            }
            return 0;
        };
        let rankData = {selfIndex: -1, items: []};
        for (let index = 0; index < data.length; index++) {
            const element = data[index];
            let score = getScore(element.KVDataList);
            if (score > 0) {
                rankData.items.push({
                    nickName: element.nickname,
                    avatarUrl: element.avatarUrl,
                    score: score,
                })
            }
        }
        rankData.items.sort(cmp);
        this._setSelfRank(rankData);
        return rankData
    }

    private async _showRankGroup(shareTicket: string) {
        let data: UserGameData[] = [];
        try {
            data = await this._getGroupScore(shareTicket);
        } catch (error) {
            cc.warn(error);
        }
        let rankData = this._getRank(data);
        this.node.emit('showRankGroup', rankData);
    }

    private _getGroupScore(shareTicket: string) {
        return new Promise<UserGameData[]>((resolve, reject)=>{
            wx.getGroupCloudStorage({
                shareTicket: shareTicket,
                keyList: [SCOREKEY],
                success: resp => resolve(resp.data),
                fail: reject,
            });
        })
    }

}
